/*
 * Copyright (C) 2025 Tsingteng MicroSystem
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
#include "nfa_base.h"
#include "nci_utils.h"
#include "hci_defs.h"
#include "hci_cmd.h"
#include "nfa_hci_api.h"
#include "nci_data.h"
#include "hci_session.h"
#include "hci_transport.h"
#include "nci_feature.h"

/**
 * @brief HCI指令拼接和处理
 *
 * @note 根据ETSI_TS_102_622 V13.0.0 版本规范实现
 */
#if IS_FEATURE_ON(NCI_FEATURE_HCI)

/**
 * @brief 设置param
 * @param[in] pipe   操作的pipe
 * @param[in] param  param内容，包含param的index、len和value
 * @return 成功时返回NCI_STATUS_OK
 *
 * @note ETSI_TS_102_622 6.1.2.1 ANY_SET_PARAMETER
 */
tNCI_STATUS hci_cmd_any_set_param(uint8_t pipe, const tHCI_PARAM *param) {
    tNCI_STATUS status;
    uint16_t rsp_len = 0;
    uint8_t *rsp = NULL;
    status = hci_process_hcp_message(pipe, HCI_HCP_TYPE_CMD, HCI_INS_ANY_SET_PARAM, (param->len + 1), &param->index, &rsp_len, &rsp);
    if (NCI_STATUS_OK != status) {
        NFCLOG_W("process hcp message ret:%d", status);
        goto exit;
    }
    // 应该收到ANY_OK并且不带其他数据
    if ((rsp_len == 1) && (NULL != rsp)) {
        if (HCI_HCP_TYPE_RSP != ((rsp[0] & HCI_HCP_TYPE_MASK) >> HCI_HCP_TYPE_OFFSET)) {
            NFCLOG_W("not a rsp message");
            status = NCI_STATUS_EXT_FAILED;
        } else {
            if (HCI_RSP_ANY_OK != (rsp[0] & HCI_RSP_MASK)) {
                NFCLOG_W("ins failed status:%02X", (rsp[0] & HCI_RSP_MASK));
                status = NCI_STATUS_EXT_FAILED;
            }
        }
    } else {
        NFCLOG_W("invalid rsp");
        status = NCI_STATUS_EXT_FAILED;
    }
    if (rsp) {
        osi_free(rsp);
        rsp = NULL;
    }
exit:
    return status;
}

/**
 * @brief 获取指定param值
 * @param[in] pipe         要操作的pipje
 * @param[in] param_index  要获取的param index
 * @param[out] param       获取到的param值，由调用者释放内存
 * @return 成功时返回NCI_STATUS_OK
 *
 * @note ETSI_TS_102_622 6.1.2.2 ANY_GET_PARAMETER
 */
tNCI_STATUS hci_cmd_any_get_param(uint8_t pipe, uint8_t param_index, tHCI_PARAM **param) {
    tNCI_STATUS status;
    uint16_t rsp_len = 0;
    uint8_t *rsp = NULL;
    status = hci_process_hcp_message(pipe, HCI_HCP_TYPE_CMD, HCI_INS_ANY_GET_PARAM, 1, &param_index, &rsp_len, &rsp);
    if (NCI_STATUS_OK != status) {
        NFCLOG_W("process hcp message ret:%d", status);
        goto exit;
    }
    // rsp的格式为状态字+param内容
    if ((rsp_len > 0) && (NULL != rsp)) {
        if (HCI_HCP_TYPE_RSP != ((rsp[0] & HCI_HCP_TYPE_MASK) >> HCI_HCP_TYPE_OFFSET)) {
            NFCLOG_W("not a rsp message");
            status = NCI_STATUS_EXT_FAILED;
            goto clean;
        }
        if (HCI_RSP_ANY_OK != (rsp[0] & HCI_RSP_MASK)) {
            NFCLOG_W("ins failed status:%02X", (rsp[0] & HCI_RSP_MASK));
            status = NCI_STATUS_EXT_FAILED;
        }
        if (rsp_len < 2) {
            NFCLOG_W("no value in rsp");
            status = NCI_STATUS_EXT_FAILED;
            goto clean;
        }
        *param = osi_malloc(sizeof(tHCI_PARAM) + rsp_len - 1);
        if (NULL == *param) {
            NFCLOG_W("malloc for rsp failed");
            status = NCI_STATUS_EXT_FAILED;
            goto clean;
        }
        (*param)->index = param_index;
        (*param)->len = rsp_len - 1;
        if (!osi_memcpy_s((*param)->dat, ((*param)->len), (rsp + 1), (rsp_len - 1))) {
            NFCLOG_W("memcpy failed");
            osi_free(*param);
            *param = NULL;
            status = NCI_STATUS_EXT_COPY_FAILED;
            goto clean;
        }
        NFCLOG_D("get param:%02X success len:%d", param_index, (*param)->len);
    } else {
        NFCLOG_W("invalid rsp");
        status = NCI_STATUS_EXT_FAILED;
    }
clean:
    if (rsp) {
        osi_free(rsp);
        rsp = NULL;
    }
exit:
    return status;
}

/**
 * @brief 打开pipe
 * @details 打开pipe操作应当在一个已经closed的pipe上
 * @param pipe[in] 要打开的pipe
 * @return 成功时返回NCI_STATUS_OK
 *
 * @note ETSI_TS_102_622 6.1.2.3 ANY_OPEN_PIPE
 */
tNCI_STATUS hci_cmd_any_open_pipe(uint8_t pipe) {
    tNCI_STATUS status;
    uint16_t rsp_len = 0;
    uint8_t *rsp = NULL;
    status = hci_process_hcp_message(pipe, HCI_HCP_TYPE_CMD, HCI_INS_ANY_OPEN_PIPE, 0, NULL, &rsp_len, &rsp);
    if (NCI_STATUS_OK != status) {
        NFCLOG_W("process hcp message ret:%d", status);
        goto exit;
    }
    // 如果操作的对象是host controller，那应该收到ANY_OK并且不带其他数据
    // 如果操作的对象是host，那应该收到ANY_OK加上已经打开的pipe数量
    if (((rsp_len == 1) || (rsp_len == 2)) && (NULL != rsp)) {
        if (HCI_HCP_TYPE_RSP != ((rsp[0] & HCI_HCP_TYPE_MASK) >> HCI_HCP_TYPE_OFFSET)) {
            NFCLOG_W("not a rsp message");
            status = NCI_STATUS_EXT_FAILED;
        } else {
            // pipe重复open，也是回复ANY_OK，不需要特殊处理
            if (HCI_RSP_ANY_OK != (rsp[0] & HCI_RSP_MASK)) {
                NFCLOG_W("ins failed status:%02X", (rsp[0] & HCI_RSP_MASK));
                status = NCI_STATUS_EXT_FAILED;
            }
        }
    } else {
        NFCLOG_W("invalid rsp");
        status = NCI_STATUS_EXT_FAILED;
    }

    if ((rsp_len > 0) && (NULL != rsp)) {
        NFCLOG_D("rsp_len:%d status:%02X", rsp_len, rsp[0]);
        osi_free(rsp);
    }
exit:
    if (NCI_STATUS_OK == status) {
        // 指令执行成功后更新本地pipe缓存
        hci_session_update_pipe_status(pipe, true);
    }
    return status;
}

/**
 * @brief 关闭pipie
 * @param pipe[in] 要关闭的pipe
 * @return 成功时返回NCI_STATUS_OK
 *
 * @note ETSI_TS_102_622 6.1.2.4 ANY_CLOSE_PIPE
 */
tNCI_STATUS hci_cmd_any_close_pipe(uint8_t pipe) {
    tNCI_STATUS status;
    uint16_t rsp_len = 0;
    uint8_t *rsp = NULL;
    status = hci_process_hcp_message(pipe, HCI_HCP_TYPE_CMD, HCI_INS_ANY_CLOSE_PIPE, 0, NULL, &rsp_len, &rsp);
    if (NCI_STATUS_OK != status) {
        NFCLOG_W("process hcp message ret:%d", status);
        goto exit;
    }
    // 应该收到ANY_OK并且不带其他数据
    if ((rsp_len == 1) && (NULL != rsp)) {
        if (HCI_HCP_TYPE_RSP != ((rsp[0] & HCI_HCP_TYPE_MASK) >> HCI_HCP_TYPE_OFFSET)) {
            NFCLOG_W("not a rsp message");
            status = NCI_STATUS_EXT_FAILED;
        } else {
            if (HCI_RSP_ANY_OK != (rsp[0] & HCI_RSP_MASK)) {
                NFCLOG_W("ins failed status:%02X", (rsp[0] & HCI_RSP_MASK));
                status = NCI_STATUS_EXT_FAILED;
            }
        }
    } else {
        NFCLOG_W("invalid rsp");
        status = NCI_STATUS_EXT_FAILED;
    }
    if (rsp) {
        osi_free(rsp);
        rsp = NULL;
    }
exit:
    if (NCI_STATUS_OK == status) {
        // 指令执行成功后更新本地pipe缓存
        hci_session_update_pipe_status(pipe, false);
    }
    return status;
}

/**
 * @brief 创建pipe
 * @details 创建动态pipe，创建pipe之前应当把远端host加入到WHITELIST中以标记这个host是合法的
 * @param src_gate[in]   本地host的gate id
 * @param dest_host[in]  远端host id
 * @param dest_gate[in]  远端host的gate id
 * @param pipe[out]      host controller分配的pipe id
 * @return 成功时返回NCI_STATUS_OK
 *
 * @note ETSI_TS_102_622 6.1.3.1 ADM_CREATE_PIPE
 */
tNCI_STATUS hci_cmd_adm_create_pipe(uint8_t src_gate, uint8_t dest_host, uint8_t dest_gate, uint8_t *pipe) {
    tNCI_STATUS status;
    uint16_t rsp_len = 0;
    uint8_t *rsp = NULL;
    uint8_t params[3];
    params[0] = src_gate;
    params[1] = dest_host;
    params[2] = dest_gate;
    status = hci_process_hcp_message(HCI_STATIC_PIPE_ADMIN, HCI_HCP_TYPE_CMD, HCI_INS_ADM_CREATE_PIPE, sizeof(params), params, &rsp_len, &rsp);
    if (NCI_STATUS_OK != status) {
        NFCLOG_W("process hcp message ret:%d", status);
        goto exit;
    }
    // rsp的格式应当是ANY_OK+src_host+src_gate+dest_host+dest_gate+pipe
    if ((rsp_len == 6) && (NULL != rsp)) {
        if (HCI_HCP_TYPE_RSP != ((rsp[0] & HCI_HCP_TYPE_MASK) >> HCI_HCP_TYPE_OFFSET)) {
            NFCLOG_W("not a rsp message");
            status = NCI_STATUS_EXT_FAILED;
        } else {
            if (HCI_RSP_ANY_OK != (rsp[0] & HCI_RSP_MASK)) {
                NFCLOG_W("ins failed status:%02X", (rsp[0] & HCI_RSP_MASK));
                status = NCI_STATUS_EXT_FAILED;
                goto clean;
            }
            // 检查返回的pipe参数是否一致
            if ((HCI_HOST_ID_DH != rsp[1]) || (src_gate != rsp[2]) || (dest_host != rsp[3]) || (dest_gate != rsp[4])) {
                NFCLOG_W("wrong pipe recieve!");
                NFCLOG_W("requesting pipe:src_host:%02X src_gate:%02X dest_host:%02X dest_gate:%02X", HCI_HOST_ID_DH, src_gate, dest_host, dest_gate);
                NFCLOG_W("host controller return pipe:src_host:%02X src_gate:%02X dest_host:%02X dest_gate:%02X", rsp[1], rsp[2], rsp[3], rsp[4]);
                status = NCI_STATUS_EXT_FAILED;
                goto clean;
            }
            *pipe = rsp[5];
            NFCLOG_D("got pipe id:%d", *pipe);
        }
    } else {
        NFCLOG_W("invalid rsp");
        status = NCI_STATUS_EXT_FAILED;
    }
clean:
    if (rsp) {
        osi_free(rsp);
        rsp = NULL;
    }
exit:
    if (NCI_STATUS_OK == status) {
        // 指令执行成功后更新本地pipe缓存
        hci_session_add_pipe(*pipe, src_gate, dest_host, dest_gate, false);
    }
    return status;
}

/**
 * @brief 删除pipe
 * @details 只能删除与本地host相关的pipe
 * @param pipe[in] 需要删除的pipe
 * @return 成功时返回NCI_STATUS_OK
 *
 * @note ETSI_TS_102_622 6.1.3.3 ADM_DELETE_PIPE
 */
tNCI_STATUS hci_cmd_adm_delete_pipe(uint8_t pipe) {
    tNCI_STATUS status;
    uint16_t rsp_len = 0;
    uint8_t *rsp = NULL;
    status = hci_process_hcp_message(HCI_STATIC_PIPE_ADMIN, HCI_HCP_TYPE_CMD, HCI_INS_ADM_DELETE_PIPE, 1, &pipe, &rsp_len, &rsp);
    if (NCI_STATUS_OK != status) {
        NFCLOG_W("process hcp message ret:%d", status);
        goto exit;
    }
    // 应该收到ANY_OK并且不带其他数据
    if ((rsp_len == 1) && (NULL != rsp)) {
        if (HCI_HCP_TYPE_RSP != ((rsp[0] & HCI_HCP_TYPE_MASK) >> HCI_HCP_TYPE_OFFSET)) {
            NFCLOG_W("not a rsp message");
            status = NCI_STATUS_EXT_FAILED;
        } else {
            if (HCI_RSP_ANY_OK != (rsp[0] & HCI_RSP_MASK)) {
                NFCLOG_W("ins failed status:%02X", (rsp[0] & HCI_RSP_MASK));
                status = NCI_STATUS_EXT_FAILED;
            }
        }
    } else {
        NFCLOG_W("invalid rsp");
        status = NCI_STATUS_EXT_FAILED;
    }
    if (rsp) {
        osi_free(rsp);
        rsp = NULL;
    }
exit:
    if (NCI_STATUS_OK == status) {
        // 指令执行成功后更新本地pipe缓存
        hci_session_delete_pipe(pipe);
    }
    return status;
}

/**
 * @brief 清除所有pipe
 * @details 清除所有本地host相关dynamic pipe，关闭所有static pipe，并把所有static pipe的参数恢复到默认值
 * @return 成功时返回NCI_STATUS_OK
 *
 * @note ETSI_TS_102_622 6.1.3.5 ADM_CLEAR_ALL_PIPE
 */
tNCI_STATUS hci_cmd_adm_clear_all_pipe(void) {
    tNCI_STATUS status;
    uint16_t rsp_len = 0;
    uint8_t *rsp = NULL;
    const uint8_t id_ref_data[2] = {0x12, 0x34}; // TODO ETSI_TS_102_622 6.1.4.5 Identity reference data应当包含随机数
    status = hci_process_hcp_message(HCI_STATIC_PIPE_ADMIN, HCI_HCP_TYPE_CMD, HCI_INS_ADM_CLEAR_ALL_PIPE, sizeof(id_ref_data), id_ref_data, &rsp_len, &rsp);
    if (NCI_STATUS_OK != status) {
        NFCLOG_W("process hcp message ret:%d", status);
        goto exit;
    }
    // 应该收到ANY_OK并且不带其他数据
    if ((rsp_len == 1) && (NULL != rsp)) {
        if (HCI_HCP_TYPE_RSP != ((rsp[0] & HCI_HCP_TYPE_MASK) >> HCI_HCP_TYPE_OFFSET)) {
            NFCLOG_W("not a rsp message");
            status = NCI_STATUS_EXT_FAILED;
            goto clean;
        }
        if (HCI_RSP_ANY_OK != (rsp[0] & HCI_RSP_MASK)) {
            NFCLOG_W("ins failed status:%02X", (rsp[0] & HCI_RSP_MASK));
            status = NCI_STATUS_EXT_FAILED;
        }
    } else {
        NFCLOG_W("invalid rsp");
        status = NCI_STATUS_EXT_FAILED;
    }
clean:
    if (rsp) {
        osi_free(rsp);
        rsp = NULL;
    }
exit:
    if (NCI_STATUS_OK == status) {
        // 指令执行成功后更新本地pipe缓存
        hci_session_clear_all_pipes();
    }
    return status;
}

#endif // IS_FEATURE_ON(NCI_FEATURE_HCI)
